package com.itholmes;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.itholmes.pojo.Handler;

//模拟实现SpringMVC容器，底层@RequestMapping的映射
public class DispatcherServlet extends HttpServlet{
	
	Map<String,Handler> ioc_final = new HashMap<String, Handler>();
	
	/*
	  	<init-param>
      		<param-name>contextConfigLocation</param-name>
      		<param-value>classpath:spring-mvc.xml</param-value>
    	</init-param>	
    	在init中完成上面的内容：
	 */
	@Override
	public void init() throws ServletException {
		//完成initparam对应的servletConfig配置
		ServletConfig config = getServletConfig();
		String initParameter = config.getInitParameter("contextConfigLocation");
		boolean contains = initParameter.contains(":");
		String trim = null;
		if(contains) {
			String[] split = initParameter.split(":");
			trim = split[1].trim();
		}else {
			trim = initParameter.trim();
		}
		//创建SpringMVC的ioc1容器
		ClassPathXmlApplicationContext ioc1 = new ClassPathXmlApplicationContext(trim);
		//遍历ioc1中的类的名字
		String[] names = ioc1.getBeanDefinitionNames();
		//根据每个name从容器中获取出对应的对象
		for (String name : names) {
			//ioc1容器中每一个对应的对象
			Object obj = ioc1.getBean(name);
			Class<? extends Object> c = obj.getClass();
			//判断有没有Controller这个注解
			Controller controller = c.getAnnotation(Controller.class);
			if(controller!=null) {
				//说明有@Controller注解
				//获取类的RequestMapping映射
				//获取出全部方法，看看那个方法上面有@RequestMapping
				Method[] methods = c.getDeclaredMethods();
				for (Method method : methods) {
					RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
					if(requestMapping!=null) {
						//说明有@RequestMapping注解,因为注解本身就有String[] values()的内容，所以这里我们可以直接调用。
						String[] values = requestMapping.value();
						//遍历多个path建立映射关系
						for (String value : values) {
							//调用反射方法的三要素：method.invoke(obj,args)
							//因为这里要设计到三个内容映射，method方法，obj对象，args参数。我们可以通过面向对象创建对象来存储。
							Handler handler = new Handler();
							handler.setObj(obj);
							handler.setMethod(method);
							//args参数就忽略了。
							
							//将映射关系注入到ioc_final的容器中。
							ioc_final.put(value, handler);
							System.out.println();
						}
					}else {
						//说明没有@RequestMapping注解
					}
					
				}
			}else {
				//说明没有@Controller注解
			}
		}
		System.out.println();
	}
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//接受每次请求
		//获取到每次的请求，调用对应的操作
		String uri = req.getRequestURI();//获取uri路径，包含项目名
		//去除项目名
		int indexOf = uri.indexOf("/",1);
		String substring = uri.substring(indexOf);
		//从ioc_final中拿到对应的映射三要素
		Handler handler = ioc_final.get(substring);
		
		if(handler==null) {
			//说明容器中没有该路径，返回404
			resp.getWriter().write("404");
			return;
		}
		
		//之后就是调用对应的映射方法就可以了
		Object invoke = null;
		try {
			invoke = handler.getMethod().invoke(handler.getObj(), handler.getArgs());
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//最后将结果返回
		resp.getWriter().write(invoke.toString());
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		this.doGet(req, resp);
	}
}
